﻿#include <xy/ais/point.h>

namespace xy
{

namespace ais
{

using namespace geom;

point::point(std::shared_ptr<vec3> p) : m_point(p)
{
}

std::shared_ptr<vec3> point::pnt() const
{
    return m_point;
}

bool point::collision(msg_mouse *msg)
{
    // 获得屏幕点和鼠标位置
    vec3f S = msg->screenMapping(convert<float>(*m_point));
    vec2f q(S.x(), S.y());
    vec2f p = msg->movePos;

    // <= 赋予选取优先级
    if (S.z() <= msg->depth && (p - q).modulus() <= 5)
    {
        msg->depth = S.z();
        msg->captured = this;
        return true;
    }
    return false;
}

void point::visit(msg_init *msg)
{
    if (msg->factory)
        m_renderer.reset(msg->factory->create_product("point"));
}

void point::visit(msg_move *msg)
{
    vec3 n = convert<double>(msg->dir);
    vec3 p = convert<double>(msg->pos);
    *m_point = p + n * dot(n, *m_point - p);

    // 调用父类方法更新
    object::visit(msg);
}

point_auxiliary::point_auxiliary(std::function<vec3()> getter, std::function<void(vec3)> setter)
    : point(nullptr), m_getter(getter), m_setter(setter)
{
    // 初始化
    m_point = std::make_shared<vec3>(getter());
}

void point_auxiliary::visit(msg_update *msg)
{
    *m_point = m_getter();

    // 调用父类方法更新
    object::visit(msg);
}

void point_auxiliary::visit(msg_move *msg)
{
    // 拦截上层移动消息
    if (m_status != Status::Pressed)
        return;

    vec3 n = convert<double>(msg->dir);
    vec3 p = convert<double>(msg->pos);
    *m_point = p + n * dot(n, *m_point - p);

    // 先赋值，然后再重赋值，进行双重更新
    m_setter(*m_point);
    *m_point = m_getter();

    // 调用父类方法更新
    object::visit(msg);
}

} // namespace ais

} // namespace xy